package com.gitee.feizns.dynamic;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

/**
 * <b>Map操作工具类</b>
 * @author feizns
 * @since 2019/6/21
 */
public abstract class MapUtils {

    /**
     * <b>创建key为String类型value为Object类型的Map（默认使用{@link LinkedHashMap}）</b>
     * <pre>{@code
     *  Map<String, Object> map = MapUtils.create("id", "1", "name", "feizns")
     *  System.out.println(map);    //{id=1, name=feizns}
     * }</pre>
     * @param entries 键值对
     * @return 以entry为键值的Map
     */
    public static Map<String, Object> create(Object... entries){
        List<Map.Entry<String, Object>> entriesList = new ArrayList<>();
        for (int i = 0; i < entries.length; i+=2) {
            if ( i + 1 < entries.length )
                entriesList.add(entry(entries[i] != null ? entries[i].toString() : null, entries[i + 1]));
        }
        return create(LinkedHashMap::new, entriesList);
    }

    /**
     * <b>创建Map包含entries中的所有键值（默认使用{@link LinkedHashMap}）</b>
     * <pre>{@code
     *  Map<String, Object> map = MapUtils.create(MapUtils.entry("id", "654321"), MapUtils.entry("name", "FEIZNS"));
     *  System.out.println(map);    //{id=654321, name=FEIZNS}
     * }</pre>
     * @see #create(Supplier, Map.Entry[])
     * @param entries 键值对列表
     * @return 以entries中的键值为键值的Map
     */
    @SafeVarargs
    public static <K, V> Map<K, V> create(Map.Entry<K, V>... entries){
        return create(LinkedHashMap::new, entries);
    }

    /**
     * <b>创建Map包含entries中的所有键值（默认使用{@link LinkedHashMap}）</b>
     * <pre>{@code
     *  Iterable<Map.Entry<String, Object>> entries = Arrays.asList(MapUtils.entry("id", "654321"), MapUtils.entry("name", "FEIZNS"));
     *  Map<String, Object> map = MapUtils.create(entries);
     *  System.out.println(map);    //{id=654321, name=FEIZNS}
     * }</pre>
     * @see #create(Supplier, Iterable)
     * @param entries 键值对列表
     * @return 以entries中的键值为键值的Map
     */
    public static <K, V> Map<K, V> create(Iterable<Map.Entry<K, V>> entries){
        return create(LinkedHashMap::new, entries);
    }

    /**
     * <b>创建Map包含entries中的所有键值</b>
     * <pre>{@code
     *  Map<Integer, Object> map = MapUtils.create(TreeMap::new, MapUtils.entry(3, "1"), MapUtils.entry(2, "2"), MapUtils.entry(1, "3"));
     *  System.out.println(map);    //{1=3, 2=2, 3=1}
     * }</pre>
     * @param entries 键值对列表
     * @return 以entries中的键值为键值的Map
     */
    @SafeVarargs
    public static <K, V> Map<K, V> create(Supplier<Map<K, V>> supplier, Map.Entry<K, V>... entries){
        return create(supplier, Arrays.asList(entries));
    }

    /**
     * <b>创建Map包含entries中的所有键值</b>
     * <pre>{@code
     *  Iterable<Map.Entry<Integer, Object>> entries = Arrays.asList(MapUtils.entry(2, "654321"), MapUtils.entry(1, "FEIZNS"));
     *  Map<Integer, Object> map = MapUtils.create(TreeMap::new, entries);
     *  System.out.println(map);    //{1=FEIZNS, 2=654321}
     * }</pre>
     * @param entries 键值对列表
     * @return 以entries中的键值为键值的Map
     */
    public static <K, V> Map<K, V> create(Supplier<Map<K, V>> supplier, Iterable<Map.Entry<K, V>> entries){
        Map<K, V> map = supplier.get();
        for (Map.Entry<K, V> entry : entries)
            map.put(entry.getKey(), entry.getValue());
        return map;
    }

    /**
     * <b>创建一个简单的Map.Entry<K, V></b>
     * @param key 键
     * @param value 值
     * @param <K> 键类型
     * @param <V> 值类型
     * @return 返回一个包含键值的Map.Entry对象
     */
    public static <K, V> Map.Entry<K, V> entry(K key, V value) {
        return new SimpleEntryImpl<>(key, value);
    }

    /**
     * <b>如果为k中没有值则为其添加值</b>
     * @param map {@link Map}
     * @param k 键
     * @param supplier 值提供者
     * @param <K> 键类型
     * @param <V> 值类型
     * @return 返回参数kvMap
     */
    public static <K, V> Map<K, V> putIfAbsent(Map<K, V> map, K k, Supplier<V> supplier) {
        V v = map.get(k);
        if ( v == null )
            map.put(k, supplier.get());
        return map;
    }

    /**
     * <b>简单的Map.Entry的实现类</b>
     * @param <K> 键类型
     * @param <V> 值类型
     */
    private static class SimpleEntryImpl<K, V> implements Map.Entry<K, V> {

        private final K k;
        private V v;

        public SimpleEntryImpl(K k, V v) {
            this.k = k;
            this.v = v;
        }

        @Override
        public K getKey() {
            return k;
        }

        @Override
        public V getValue() {
            return v;
        }

        @Override
        public V setValue(V value) {
            V oldValue = v;
            v = value;
            return oldValue;
        }

    }

}
